home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gp_os2.c < prev    next >
C/C++ Source or Header  |  1996-09-05  |  24KB  |  908 lines

  1. /* Copyright (C) 1992, 1995, 1996 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gp_os2.c */
  20. /* Common platform-specific routines for OS/2 and MS-DOS */
  21. /* compiled with GCC/EMX */
  22.  
  23. #define INCL_DOS
  24. #define INCL_SPL
  25. #define INCL_SPLDOSPRINT
  26. #define INCL_SPLERRORS
  27. #define INCL_BASE
  28. #define INCL_ERRORS
  29. #define INCL_WIN
  30. #include <os2.h>
  31.  
  32. #include "stdio_.h"
  33. #include "string_.h"
  34. #include <fcntl.h>
  35.  
  36. #ifdef __IBMC__
  37. #define popen fopen    /* doesn't support popen */
  38. #define pclose fclose    /* doesn't support pclose */
  39. #else
  40. #include <dos.h>
  41. #endif
  42. /* Define the regs union tag for short registers. */
  43. #  define rshort x
  44. #define intdos(a,b) _int86(0x21, a, b)
  45.  
  46. #include "memory_.h"
  47. #include "string_.h"
  48. #include "gx.h"
  49. #include "gsexit.h"
  50. #include "gsmemory.h"
  51. #include "gsstruct.h"
  52. #include "gp.h"
  53. #include "gsutil.h"
  54. #include "stdlib.h"        /* need _osmode, exit */
  55. #include "time_.h"
  56. #include <time.h>        /* should this be in time_.h? */
  57. #include "gdevpm.h"
  58. #ifdef __EMX__
  59. #include <sys/emxload.h>
  60. #endif
  61.  
  62. #if defined(__DLL__) && defined( __EMX__)
  63. /* This isn't provided in any of the libraries */
  64. /* We set this to the process environment in gp_init */
  65. char *fake_environ[3] = {"", NULL, NULL};
  66. char **environ = fake_environ;
  67. char **_environ = fake_environ;
  68. HWND hwndtext = (HWND)NULL;
  69. #endif
  70.  
  71. #ifdef __DLL__
  72. /* use longjmp instead of exit when using DLL */
  73. #include <setjmp.h>
  74. extern jmp_buf gsdll_env;
  75. #endif
  76.  
  77. #ifdef __DLL__
  78. #define isos2 TRUE
  79. #else
  80. #define isos2 (_osmode == OS2_MODE)
  81. #endif
  82. char pm_prntmp[256];    /* filename of printer spool temporary file */
  83.  
  84.  
  85. /* ------ Miscellaneous ------ */
  86.  
  87. /* Get the string corresponding to an OS error number. */
  88. /* All reasonable compilers support it. */
  89. const char *
  90. gp_strerror(int errnum)
  91. {    return strerror(errnum);
  92. }
  93.  
  94. /* use Unix version for date and time */
  95. /* ------ Date and time ------ */
  96.  
  97. /* Read the current time (in seconds since Jan. 1, 1970) */
  98. /* and fraction (in nanoseconds since midnight). */
  99. void
  100. gp_get_realtime(long *pdt)
  101. {    struct timeval tp;
  102.     struct timezone tzp;
  103.  
  104.     if ( gettimeofday(&tp, &tzp) == -1 )
  105.        {    lprintf("Ghostscript: gettimeofday failed!\n");
  106.         gs_exit(1);
  107.        }
  108.  
  109.     /* tp.tv_sec is #secs since Jan 1, 1970 */
  110.     pdt[0] = tp.tv_sec;
  111.     pdt[1] = tp.tv_usec * 1000;
  112.  
  113. #ifdef DEBUG_CLOCK
  114.     printf("tp.tv_sec = %d  tp.tv_usec = %d  pdt[0] = %ld  pdt[1] = %ld\n",
  115.         tp.tv_sec, tp.tv_usec, pdt[0], pdt[1]);
  116. #endif
  117. }
  118.  
  119. /* Read the current user CPU time (in seconds) */
  120. /* and fraction (in nanoseconds).  */
  121. void
  122. gp_get_usertime(long *pdt)
  123. {    gp_get_realtime(pdt);    /* Use an approximation for now.  */
  124. }
  125.  
  126.  
  127. /* ------ Console management ------ */
  128.  
  129. /* Answer whether a given file is the console (input or output). */
  130. /* This is not a standard gp procedure, */
  131. /* but the MS Windows configuration needs it, */
  132. /* and other MS-DOS configurations might need it someday. */
  133. /* Don't know if it is needed for OS/2. */
  134. bool
  135. gp_file_is_console(FILE *f)
  136. {
  137. #ifndef __DLL__
  138.     if (!isos2) {
  139.     union REGS regs;
  140.     if ( f == NULL )
  141.         return false;
  142.     regs.h.ah = 0x44;    /* ioctl */
  143.     regs.h.al = 0;        /* get device info */
  144.     regs.rshort.bx = fileno(f);
  145.     intdos(®s, ®s);
  146.     return ((regs.h.dl & 0x80) != 0 && (regs.h.dl & 3) != 0);
  147.     }
  148. #endif
  149.     if ( (f==stdin) || (f==stdout) || (f==stderr) )
  150.     return true;
  151.     return false;
  152. }
  153.  
  154. /* ------ File naming and accessing ------ */
  155.  
  156. /* Define the character used for separating file names in a list. */
  157. const char gp_file_name_list_separator = ';';
  158.  
  159. /* Define the default scratch file name prefix. */
  160. const char gp_scratch_file_name_prefix[] = "gs";
  161.  
  162. /* Define the name of the null output file. */
  163. const char gp_null_file_name[] = "nul";
  164.  
  165. /* Define the name that designates the current directory. */
  166. const char gp_current_directory_name[] = ".";
  167.  
  168. /* Define the string to be concatenated with the file mode */
  169. /* for opening files without end-of-line conversion. */
  170. const char gp_fmode_binary_suffix[] = "b";
  171. /* Define the file modes for binary reading or writing. */
  172. const char gp_fmode_rb[] = "rb";
  173. const char gp_fmode_wb[] = "wb";
  174.  
  175. /* Answer whether a file name contains a directory/device specification, */
  176. /* i.e. is absolute (not directory- or device-relative). */
  177. bool
  178. gp_file_name_is_absolute(const char *fname, uint len)
  179. {    /* A file name is absolute if it contains a drive specification */
  180.     /* (second character is a :) or if it start with 0 or more .s */
  181.     /* followed by a / or \. */
  182.     if ( len >= 2 && fname[1] == ':' )
  183.       return true;
  184.     while ( len && *fname == '.' )
  185.       ++fname, --len;
  186.     return (len && (*fname == '/' || *fname == '\\'));
  187. }
  188.  
  189. /* Answer the string to be used for combining a directory/device prefix */
  190. /* with a base file name.  The file name is known to not be absolute. */
  191. const char *
  192. gp_file_name_concat_string(const char *prefix, uint plen,
  193.   const char *fname, uint len)
  194. {    if ( plen > 0 )
  195.       switch ( prefix[plen - 1] )
  196.        {    case ':': case '/': case '\\': return "";
  197.        };
  198.     return "\\";
  199. }
  200.  
  201.  
  202. /* ------ File enumeration ------ */
  203.  
  204.  
  205. struct file_enum_s {
  206.     FILEFINDBUF3 findbuf;
  207.     HDIR hdir;
  208.     char *pattern;
  209.     int patlen;            /* orig pattern length */
  210.     int pat_size;            /* allocate space for pattern */
  211.     int head_size;            /* pattern length through last */
  212.                     /* :, / or \ */
  213.     int first_time;
  214.     gs_memory_t *memory;
  215. };
  216. gs_private_st_ptrs1(st_file_enum, struct file_enum_s, "file_enum",
  217.   file_enum_enum_ptrs, file_enum_reloc_ptrs, pattern);
  218.  
  219. /* Initialize an enumeration.  may NEED WORK ON HANDLING * ? \. */
  220. file_enum *
  221. gp_enumerate_files_init(const char *pat, uint patlen, gs_memory_t *mem)
  222. {    file_enum *pfen = gs_alloc_struct(mem, file_enum, &st_file_enum, "gp_enumerate_files");
  223.     int pat_size = 2 * patlen + 1;
  224.     char *pattern;
  225.     int hsize = 0;
  226.     int i;
  227.     if ( pfen == 0 ) return 0;
  228.  
  229.     /* pattern could be allocated as a string, */
  230.     /* but it's simpler for GC and freeing to allocate it as bytes. */
  231.  
  232.     pattern = (char *)gs_alloc_bytes(mem, pat_size,
  233.                      "gp_enumerate_files(pattern)");
  234.     if ( pattern == 0 ) return 0;
  235.     memcpy(pattern, pat, patlen);
  236.     /* find directory name = header */
  237.     for ( i = 0; i < patlen; i++ )
  238.     {    switch ( pat[i] )
  239.         {
  240.         case '\\':
  241.             if ( i + 1 < patlen && pat[i + 1] == '\\' )
  242.                 i++;
  243.             /* falls through */
  244.         case ':':
  245.         case '/':
  246.             hsize = i + 1;
  247.         }
  248.     }
  249.     pattern[patlen] = 0;
  250.     pfen->pattern = pattern;
  251.     pfen->patlen = patlen;
  252.     pfen->pat_size = pat_size;
  253.     pfen->head_size = hsize;
  254.     pfen->memory = mem;
  255.     pfen->first_time = 1;
  256.     pfen->hdir = HDIR_CREATE;
  257.     return pfen;
  258. }
  259.  
  260. /* Enumerate the next file. */
  261. uint
  262. gp_enumerate_files_next(file_enum *pfen, char *ptr, uint maxlen)
  263. {
  264.     APIRET rc;
  265.     ULONG cFilenames = 1;
  266.     if (!isos2) {
  267.     /* CAN'T DO IT SO JUST RETURN THE PATTERN. */
  268.     if ( pfen->first_time )
  269.     {    char *pattern = pfen->pattern;
  270.         uint len = strlen(pattern);
  271.         pfen->first_time = 0;
  272.         if ( len > maxlen )
  273.             return maxlen + 1;
  274.         strcpy(ptr, pattern);
  275.         return len;
  276.     }
  277.     return -1;
  278.     }
  279.  
  280.     /* else OS/2 */
  281.     if ( pfen->first_time ) {
  282.     rc = DosFindFirst(pfen->pattern, &pfen->hdir, FILE_NORMAL,
  283.         &pfen->findbuf, sizeof(pfen->findbuf), 
  284.         &cFilenames, FIL_STANDARD);
  285.     pfen->first_time = 0;
  286.     }
  287.     else {
  288.     rc = DosFindNext(pfen->hdir, &pfen->findbuf, sizeof(pfen->findbuf),
  289.         &cFilenames);
  290.     }
  291.     if (rc)
  292.     return -1;
  293.     
  294.     if (pfen->head_size + pfen->findbuf.cchName < maxlen) {
  295.         memcpy(ptr, pfen->pattern, pfen->head_size);
  296.     strcpy(ptr + pfen->head_size, pfen->findbuf.achName);
  297.     return pfen->head_size + pfen->findbuf.cchName;
  298.     }
  299.  
  300.     if (pfen->head_size >= maxlen)
  301.     return 0;    /* no hope at all */
  302.  
  303.     memcpy(ptr, pfen->pattern, pfen->head_size);
  304.     strncpy(ptr + pfen->head_size, pfen->findbuf.achName, 
  305.         maxlen - pfen->head_size - 1);
  306.     return maxlen;
  307. }
  308.  
  309. /* Clean up the file enumeration. */
  310. void
  311. gp_enumerate_files_close(file_enum *pfen)
  312. {
  313.     gs_memory_t *mem = pfen->memory;
  314.     if (isos2)
  315.         DosFindClose(pfen->hdir);
  316.     gs_free_object(mem, pfen->pattern,
  317.                "gp_enumerate_files_close(pattern)");
  318.     gs_free_object(mem, pfen, "gp_enumerate_files_close");
  319. }
  320.  
  321. /*************************************************************/
  322. /* from gp_iwatc.c and gp_itbc.c */
  323.  
  324. /* Intel processor, EMX/GCC specific routines for Ghostscript */
  325. #include <signal.h>
  326. #include "stat_.h"
  327. #include "string_.h"
  328.  
  329. /* Library routines not declared in a standard header */
  330. /* extern char *getenv(P1(const char *)); */
  331.  
  332. /* Forward declarations */
  333. private void handle_FPE(P1(int));
  334.  
  335. /* Do platform-dependent initialization. */
  336. void
  337. gp_init(void)
  338. {
  339. #if defined(__DLL__) && defined(__EMX__)
  340.     PTIB pptib;
  341.     PPIB pppib;
  342.     int i;
  343.     char *p;
  344.     /* get environment of EXE */
  345.     DosGetInfoBlocks(&pptib, &pppib);
  346.     for (i=0, p=pppib->pib_pchenv; *p; p+=strlen(p)+1)
  347.         i++;
  348.     _environ = environ = (char **)malloc((i+2) * sizeof(char *));
  349.      for (i=0, p=pppib->pib_pchenv; *p; p+=strlen(p)+1) {
  350.         environ[i] = p;
  351.         i++;
  352.     }
  353.     environ[i] = p;
  354.     i++;
  355.     environ[i] = NULL;
  356. #endif
  357.  
  358.     /* keep gsos2.exe in memory for number of minutes specified in */
  359.     /* environment variable GS_LOAD */
  360. #ifdef __EMX__
  361.     _emxload_env("GS_LOAD");
  362. #endif
  363.     /* Set up the handler for numeric exceptions. */
  364.     signal(SIGFPE, handle_FPE);
  365.     gp_init_console();
  366. }
  367.  
  368.  
  369. /* Trap numeric exceptions.  Someday we will do something */
  370. /* more appropriate with these. */
  371. private void
  372. handle_FPE(int sig)
  373. {    eprintf("Numeric exception:\n");
  374.     exit(1);
  375. }
  376.  
  377. extern int gs_exit_status;
  378. /* Do platform-dependent cleanup. */
  379. void
  380. gp_exit(int exit_status, int code)
  381. {
  382. #ifndef __DLL__
  383.     if (exit_status && (_osmode == OS2_MODE))
  384.         DosSleep(2000);
  385. #endif
  386. #if defined(__DLL__) && defined(__EMX__)
  387.     if (environ != fake_environ) {
  388.         free(environ);
  389.         environ = _environ = fake_environ;
  390.     }
  391. #endif
  392. }
  393.  
  394. /* Exit the program. */
  395. void
  396. gp_do_exit(int exit_status)
  397. {
  398. #if defined(__DLL__)
  399.     /* Use longjmp since exit would terminate caller */
  400.     /* setjmp code will check gs_exit_status */
  401.     longjmp(gsdll_env, gs_exit_status);
  402. #else
  403.     exit(exit_status);
  404. #endif
  405. }
  406.  
  407. /* ------ Printer accessing ------ */
  408. private int pm_find_queue(char *queue_name, char *driver_name);
  409. private int is_os2_spool(const char *queue);
  410. private int pm_spool(char *filename, const char *queue);
  411.   
  412. /* Put a printer file (which might be stdout) into binary or text mode. */
  413. /* This is not a standard gp procedure, */
  414. /* but all MS-DOS configurations need it. */
  415. void
  416. gp_set_printer_binary(int prnfno, int binary)
  417. {
  418. #ifndef __IBMC__
  419.     union REGS regs;
  420.     regs.h.ah = 0x44;    /* ioctl */
  421.     regs.h.al = 0;        /* get device info */
  422.     regs.rshort.bx = prnfno;
  423.     intdos(®s, ®s);
  424.     if ( ((regs.rshort.flags)&1) != 0 || !(regs.h.dl & 0x80) )
  425.         return;        /* error, or not a device */
  426.     if ( binary )
  427.         regs.h.dl |= 0x20;    /* binary (no ^Z intervention) */
  428.     else
  429.         regs.h.dl &= ~0x20;    /* text */
  430.     regs.h.dh = 0;
  431.     regs.h.ah = 0x44;    /* ioctl */
  432.     regs.h.al = 1;        /* set device info */
  433.     intdos(®s, ®s);
  434. #endif
  435. }
  436.  
  437. /* Open a connection to a printer.  A null file name means use the */
  438. /* standard printer connected to the machine, if any. */
  439. /* Return NULL if the connection could not be opened. */
  440. /* filename can be one of the following values
  441.  *   ""                Spool in default queue
  442.  *   "\\spool\queue"   Spool in "queue"
  443.  *   "|command"        open an output pipe using popen()
  444.  *   "filename"        open filename using fopen()
  445.  *   "port"            open port using fopen()
  446.  */
  447. FILE *
  448. gp_open_printer(char *fname, int binary_mode)
  449. {    FILE *pfile;
  450.     if ( (strlen(fname) == 0) || is_os2_spool(fname) ) {
  451.         if (isos2) {
  452.         /* default or spool */
  453.         if (pm_spool(NULL, fname))    /* check if spool queue valid */
  454.             return NULL;
  455.         pfile = gp_open_scratch_file(gp_scratch_file_name_prefix, 
  456.                 pm_prntmp, (binary_mode ? "wb" : "w"));
  457.         }
  458.         else
  459.         pfile = fopen("PRN", (binary_mode ? "wb" : "w"));
  460.     }
  461.     else if ( (isos2) && (fname[0] == '|') )
  462.         /* pipe */
  463.         pfile = popen(fname+1, (binary_mode ? "wb" : "w"));
  464.     else
  465.         /* normal file or port */
  466.         pfile = fopen(fname, (binary_mode ? "wb" : "w"));
  467.  
  468.     if ( pfile == (FILE *)NULL )
  469.         return (FILE *)NULL;
  470.     if (!isos2)
  471.         gp_set_printer_binary(fileno(pfile), binary_mode);
  472.     return pfile;
  473. }
  474.  
  475. /* Close the connection to the printer. */
  476. void
  477. gp_close_printer(FILE *pfile, const char *fname)
  478. {    
  479.     if ( isos2 && (fname[0] == '|') )
  480.         pclose(pfile);
  481.     else
  482.         fclose(pfile);
  483.  
  484.     if ( (strlen(fname) == 0) || is_os2_spool(fname) ) {
  485.         /* spool temporary file */
  486.         pm_spool(pm_prntmp, fname);
  487.         unlink(pm_prntmp);
  488.     }
  489. }
  490.  
  491. /* ------ Printer Spooling ------ */
  492. #ifndef NERR_BufTooSmall
  493. #define NERR_BufTooSmall 2123    /* For SplEnumQueue */
  494. #endif
  495.  
  496. /* If queue_name is NULL, list available queues */
  497. /* If strlen(queue_name)==0, return default queue and driver name */
  498. /* If queue_name supplied, return driver_name */
  499. /* returns 0 if OK, non-zero for error */
  500. private int
  501. pm_find_queue(char *queue_name, char *driver_name)
  502. {
  503.     SPLERR splerr;
  504.     USHORT jobCount;
  505.     ULONG  cbBuf;
  506.     ULONG  cTotal;
  507.     ULONG  cReturned;
  508.     ULONG  cbNeeded;
  509.     ULONG  ulLevel;
  510.     ULONG  i;
  511.     PSZ    pszComputerName;
  512.     PBYTE  pBuf;
  513.     PPRQINFO3 prq;
  514.  
  515.     ulLevel = 3L;
  516.     pszComputerName = (PSZ)NULL ;
  517.     splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, 0L, /* cbBuf */
  518.                           &cReturned, &cTotal,
  519.                           &cbNeeded, NULL);
  520.     if ( splerr == ERROR_MORE_DATA || splerr == NERR_BufTooSmall ) {
  521.        if (!DosAllocMem( (PVOID)&pBuf, cbNeeded,
  522.                          PAG_READ|PAG_WRITE|PAG_COMMIT) ) {
  523.           cbBuf = cbNeeded ;
  524.           splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, cbBuf,
  525.                                   &cReturned, &cTotal,
  526.                                   &cbNeeded, NULL);
  527.           if (splerr == NO_ERROR) {
  528.              /* Set pointer to point to the beginning of the buffer.           */
  529.              prq = (PPRQINFO3)pBuf ;
  530.  
  531.              /* cReturned has the count of the number of PRQINFO3 structures.  */
  532.              for (i=0;i < cReturned ; i++) {
  533.         if (queue_name) {
  534.             /* find queue name and return driver name */
  535.             if (strlen(queue_name)==0) {  /* use default queue */
  536.                 if ( prq->fsType & PRQ3_TYPE_APPDEFAULT )
  537.                 strcpy(queue_name, prq->pszName);
  538.             }
  539.             if (strcmp(prq->pszName, queue_name) == 0) {
  540.             char *p;
  541.             for (p=prq->pszDriverName; *p && (*p!='.'); p++)
  542.                 /* do nothing */ ;
  543.             *p = '\0';  /* truncate at '.' */
  544.             if (driver_name != NULL)
  545.                 strcpy(driver_name, prq->pszDriverName);
  546.             DosFreeMem((PVOID)pBuf) ;
  547.             return 0;
  548.             }
  549.         }
  550.         else {
  551.             /* list queue details */
  552.             if ( prq->fsType & PRQ3_TYPE_APPDEFAULT )
  553.                 fprintf(stdout, "  %s  (DEFAULT)\n", prq->pszName) ;
  554.             else
  555.                 fprintf(stdout, "  %s\n", prq->pszName) ;
  556.         }
  557.                 prq++;
  558.              }/*endfor cReturned */
  559.           }
  560.           DosFreeMem((PVOID)pBuf) ;
  561.        }
  562.     } /* end if Q level given */
  563.     else {
  564.        /* If we are here we had a bad error code. Print it and some other info.*/
  565.        fprintf(stdout, "SplEnumQueue Error=%ld, Total=%ld, Returned=%ld, Needed=%ld\n",
  566.                splerr, cTotal, cReturned, cbNeeded) ;
  567.     }
  568.     if (splerr)
  569.         return splerr;
  570.     if (queue_name)
  571.         return -1;
  572.     return 0;
  573. }
  574.  
  575.  
  576. /* return TRUE if queue looks like a valid OS/2 queue name */
  577. private int
  578. is_os2_spool(const char *queue)
  579. {
  580. char *prefix = "\\\\spool\\";  /* 8 characters long */
  581. int i;
  582.     for (i=0; i<8; i++) {
  583.     if (prefix[i] == '\\') {
  584.         if ((*queue != '\\') && (*queue != '/'))
  585.             return FALSE;
  586.     }
  587.     else if (tolower(*queue) != prefix[i])
  588.         return FALSE;
  589.     queue++;
  590.     }
  591.     return TRUE;
  592. }
  593.  
  594. #define PRINT_BUF_SIZE 16384
  595.  
  596. /* Spool file to queue */
  597. /* return 0 if successful, non-zero if error */
  598. /* if filename is NULL, return 0 if spool queue is valid, non-zero if error */
  599. private int
  600. pm_spool(char *filename, const char *queue)
  601. {
  602. HSPL hspl;
  603. PDEVOPENSTRUC pdata;
  604. PSZ  pszToken = "*";
  605. ULONG jobid;
  606. BOOL rc;
  607. char queue_name[256];
  608. char driver_name[256];
  609. char *buffer;
  610. FILE *f;
  611. int count;
  612.     if (strlen(queue)!= 0) {
  613.     /* queue specified */
  614.     strcpy(queue_name, queue+8);  /* skip over \\spool\ */
  615.     }
  616.     else {
  617.     /* get default queue */
  618.         queue_name[0] = '\0';
  619.     }
  620.     if (pm_find_queue(queue_name, driver_name)) {
  621.     /* error, list valid queue names */
  622.     fprintf(stdout, "Invalid queue name.  Use one of:\n");
  623.     pm_find_queue(NULL,NULL);
  624.     return 1;
  625.     }
  626.     if (!filename)
  627.     return 0;    /* we were only asked to check the queue */
  628.  
  629.  
  630.     if ((buffer = malloc(PRINT_BUF_SIZE)) == (char *)NULL) {
  631.     fprintf(stdout, "Out of memory in pm_spool\n");
  632.     return 1;
  633.     }
  634.     if ((f = fopen(filename, "rb")) == (FILE *)NULL) {
  635.     free(buffer);
  636.     fprintf(stdout, "Can't open temporary file %s\n", filename);
  637.     return 1;
  638.     }
  639.  
  640.     /* Allocate memory for pdata */
  641.     if ( !DosAllocMem( (PVOID)&pdata,sizeof( DEVOPENSTRUC ),
  642.          (PAG_READ|PAG_WRITE|PAG_COMMIT ) ) ) {
  643.         /* Initialize elements of pdata */
  644.         pdata->pszLogAddress      = queue_name;
  645.         pdata->pszDriverName      = driver_name;
  646.         pdata->pdriv              = NULL;
  647.         pdata->pszDataType        = "PM_Q_RAW";
  648.         pdata->pszComment         = "Ghostscript";
  649.         pdata->pszQueueProcName   = NULL;
  650.         pdata->pszQueueProcParams = NULL;
  651.         pdata->pszSpoolerParams   = NULL;
  652.         pdata->pszNetworkParams   = NULL;
  653.  
  654.         hspl = SplQmOpen( pszToken,4L,( PQMOPENDATA )pdata );
  655.         if ( hspl == SPL_ERROR ) {
  656.             fprintf(stdout, "SplQmOpen failed.\n");
  657.         DosFreeMem((PVOID)pdata);
  658.         free(buffer);
  659.         fclose(f);
  660.         return 1;    /* failed */
  661.         }
  662.  
  663.     rc = SplQmStartDoc(hspl, "Ghostscript");
  664.     if (!rc) {
  665.         fprintf(stdout, "SplQmStartDoc failed.\n");
  666.         DosFreeMem((PVOID)pdata);
  667.         free(buffer);
  668.         fclose(f);
  669.         return 1;
  670.     }
  671.     
  672.     /* loop, copying file to queue */
  673.     while (rc && (count = fread(buffer, 1, PRINT_BUF_SIZE, f)) != 0 ) {
  674.         rc = SplQmWrite(hspl, count, buffer);
  675.         if (!rc)
  676.         fprintf(stdout, "SplQmWrite failed.\n");
  677.       }
  678.     free(buffer);
  679.     fclose(f);
  680.  
  681.     if (!rc) {
  682.       fprintf(stdout, "Aborting Spooling.\n");
  683.           SplQmAbort(hspl);
  684.         }
  685.     else {
  686.         SplQmEndDoc(hspl);
  687.         rc = SplQmClose(hspl);
  688.         if (!rc)
  689.         fprintf(stdout, "SplQmClose failed.\n");
  690.     }
  691.     }
  692.     else
  693.     rc = 0;    /* no memory */
  694.     return !rc;
  695. }
  696.  
  697. /* ------ File naming and accessing ------ */
  698.  
  699. /* Create and open a scratch file with a given name prefix. */
  700. /* Write the actual file name at fname. */
  701. FILE *
  702. gp_open_scratch_file(const char *prefix, char *fname, const char *mode)
  703. {    char *temp;
  704. #ifdef __IBMC__
  705.     char *tname;
  706.     *fname = 0;
  707.     temp = getenv("TEMP");
  708.     tname = _tempnam(temp, (char *)prefix);
  709.     if (tname) {
  710.         strcpy(fname, tname);
  711.         free(tname);
  712.     }
  713. #else
  714.     if ( (temp = getenv("TEMP")) == NULL )
  715.         *fname = 0;
  716.     else
  717.     {    char last = '\\';
  718.         strcpy(fname, temp);
  719.         /* Prevent X's in path from being converted by mktemp. */
  720.         for ( temp = fname; *temp; temp++ )
  721.             *temp = last = tolower(*temp);
  722.         switch ( last )
  723.         {
  724.         default:
  725.             strcat(fname, "\\");
  726.         case ':': case '\\':
  727.             ;
  728.         }
  729.     }
  730.     strcat(fname, prefix);
  731.     strcat(fname, "XXXXXX");
  732.     mktemp(fname);
  733. #endif
  734.     return fopen(fname, mode);
  735. }
  736.  
  737. /* Open a file with the given name, as a stream of uninterpreted bytes. */
  738. FILE *
  739. gp_fopen(const char *fname, const char *mode)
  740. {    return fopen(fname, mode);
  741. }
  742.  
  743. #ifdef __DLL__
  744.  
  745. /* The DLL version must not be allowed direct access to stdin and stdout */
  746. /* Instead these are redirected to the gsdll_callback */
  747. #include "gsdll.h"
  748. #include <stdarg.h>
  749.  
  750. /* for redirecting stdin/out/err */
  751. #include "stream.h"
  752. #include "gxiodev.h"            /* must come after stream.h */
  753.  
  754.  
  755. /* ====== Substitute for stdio ====== */
  756.  
  757. /* this code has been derived from gp_mswin.c */
  758.  
  759. /* Forward references */
  760. private stream_proc_process(pm_std_read_process);
  761. private stream_proc_process(pm_std_write_process);
  762.  
  763. /* Use a pseudo IODevice to get pm_stdio_init called at the right time. */
  764. /* This is bad architecture; we'll fix it later. */
  765. private iodev_proc_init(pm_stdio_init);
  766. gx_io_device gs_iodev_wstdio = {
  767.     "wstdio", "Special",
  768.     { pm_stdio_init, iodev_no_open_device,
  769.       iodev_no_open_file, iodev_no_fopen, iodev_no_fclose,
  770.       iodev_no_delete_file, iodev_no_rename_file,
  771.       iodev_no_file_status, iodev_no_enumerate_files
  772.     }
  773. };
  774.  
  775. /* Discard the contents of the buffer when reading. */
  776. void
  777. pm_std_read_reset(stream *s)
  778. {    s_std_read_reset(s);
  779.     s->end_status = 0;
  780. }
  781.  
  782. /* Define alternate 'open' routines for our stdin/out/err streams. */
  783.  
  784. extern int iodev_stdin_open(P4(gx_io_device *, const char *, stream **,
  785.                    gs_memory_t *));
  786. private int
  787. pm_stdin_open(gx_io_device *iodev, const char *access, stream **ps,
  788.   gs_memory_t *mem)
  789. {    int code = iodev_stdin_open(iodev, access, ps, mem);
  790.     stream *s = *ps;
  791.     if ( code != 1 )
  792.       return code;
  793.     s->procs.reset = pm_std_read_reset;
  794.     s->procs.process = pm_std_read_process;
  795.     s->file = NULL;
  796.     return 0;
  797. }
  798.  
  799. extern int iodev_stdout_open(P4(gx_io_device *, const char *, stream **,
  800.                 gs_memory_t *));
  801. private int
  802. pm_stdout_open(gx_io_device *iodev, const char *access, stream **ps,
  803.   gs_memory_t *mem)
  804. {    int code = iodev_stdout_open(iodev, access, ps, mem);
  805.     stream *s = *ps;
  806.     if ( code != 1 )
  807.       return code;
  808.     s->procs.process = pm_std_write_process;
  809.     s->file = NULL;
  810.     return 0;
  811. }
  812.  
  813. extern int iodev_stderr_open(P4(gx_io_device *, const char *, stream **,
  814.                 gs_memory_t *));
  815. private int
  816. pm_stderr_open(gx_io_device *iodev, const char *access, stream **ps,
  817.   gs_memory_t *mem)
  818. {    int code = iodev_stderr_open(iodev, access, ps, mem);
  819.     stream *s = *ps;
  820.     if ( code != 1 )
  821.       return code;
  822.     s->procs.process = pm_std_write_process;
  823.     s->file = NULL;
  824.     return 0;
  825. }
  826.  
  827. /* Patch stdin/out/err to use our windows. */
  828. private int
  829. pm_stdio_init(gx_io_device *iodev, gs_memory_t *mem)
  830. {
  831.     /* If stdxxx is the console, replace the 'open' routines, */
  832.     /* which haven't gotten called yet. */
  833.  
  834.     if ( gp_file_is_console(gs_stdin) )
  835.       gs_findiodevice((const byte *)"%stdin", 6)->procs.open_device =
  836.         pm_stdin_open;
  837.  
  838.     if ( gp_file_is_console(gs_stdout) )
  839.       gs_findiodevice((const byte *)"%stdout", 7)->procs.open_device =
  840.         pm_stdout_open;
  841.  
  842.     if ( gp_file_is_console(gs_stderr) )
  843.       gs_findiodevice((const byte *)"%stderr", 7)->procs.open_device =
  844.         pm_stderr_open;
  845.  
  846.     return 0;
  847. }
  848.  
  849.  
  850. /* We should really use a private buffer for line reading, */
  851. /* because we can't predict the size of the supplied input area.... */
  852. private int
  853. pm_std_read_process(stream_state *st, stream_cursor_read *ignore_pr,
  854.   stream_cursor_write *pw, bool last)
  855. {
  856.     int count = pw->limit - pw->ptr;
  857.  
  858.     if ( count == 0 )         /* empty buffer */
  859.         return 1;
  860.  
  861.         /* callback to get more input */
  862.     count = (*pgsdll_callback)(GSDLL_STDIN, pw->ptr+1, count);
  863.     if (count == 0) {
  864.         /* EOF */
  865.         /* what should we do? */
  866.         return EOFC;
  867.     }
  868.  
  869.     pw->ptr += count;
  870.     return 1;
  871. }
  872.  
  873. private int
  874. pm_std_write_process(stream_state *st, stream_cursor_read *pr,
  875.   stream_cursor_write *ignore_pw, bool last)
  876. {    uint count = pr->limit - pr->ptr;
  877.     (*pgsdll_callback)(GSDLL_STDOUT, (char *)(pr->ptr + 1), count);
  878.     pr->ptr = pr->limit;
  879.     return 0;
  880. }
  881.  
  882. /* This is used instead of the stdio version. */
  883. /* The declaration must be identical to that in <stdio.h>. */
  884. #ifdef __EMX__
  885. int 
  886. fprintf(FILE *file, __const__ char *fmt, ...)
  887. #else
  888. int 
  889. fprintf(FILE *file, const char *fmt, ...)
  890. #endif
  891. {
  892. int count;
  893. va_list args;
  894.     va_start(args,fmt);
  895.     if ( gp_file_is_console(file) ) {
  896.         char buf[1024];
  897.         count = vsprintf(buf,fmt,args);
  898.         (*pgsdll_callback)(GSDLL_STDOUT, buf, count);
  899.     }
  900.     else {
  901.         count = vfprintf(file, fmt, args);
  902.     }
  903.     va_end(args);
  904.     return count;
  905. }
  906. #endif /* __DLL__ */
  907.  
  908.